function [trainFaces, trainLabels, meanFace, eigenFaces, weightedTrain, projectMatrix, personCount] = trainPCA(trainFolder, trainImgPerPerson, pcaRatio)
% trainPCA - 使用PCA算法训练人脸识别模型
%
% 输入:
%   trainFolder - 训练集文件夹路径
%   trainImgPerPerson - 每个人使用的训练图像数量
%   pcaRatio - 主成分贡献率(保留的信息量，0-1之间)
%
% 输出:
%   trainFaces - 训练用的人脸图像矩阵，每一列是一个图像向量
%   trainLabels - 对应的标签数组
%   meanFace - 平均脸
%   eigenFaces - 特征脸矩阵，每一列是一个特征脸
%   weightedTrain - 训练集在特征空间的投影系数
%   projectMatrix - 投影矩阵
%   personCount - 训练集中的人物数量

    disp('DEBUG: trainPCA函数开始执行');
    disp(['DEBUG: 训练文件夹路径 = ', trainFolder]);
    disp(['DEBUG: 每人图像数 = ', num2str(trainImgPerPerson)]);
    disp(['DEBUG: 主成分贡献率 = ', num2str(pcaRatio)]);
    
    % 检查文件夹是否存在
    if ~exist(trainFolder, 'dir')
        error('训练文件夹不存在: %s', trainFolder);
    end
    
    fprintf('===== PCA人脸识别训练开始 =====\n');
    
    % 1. 获取训练图像文件列表
    fprintf('【步骤1/10】正在搜索训练图像文件...\n');
    imgExtensions = {'.jpg', '.png', '.bmp', '.jpeg', '.tif'};
    allFiles = [];
    
    for i = 1:length(imgExtensions)
        pattern = ['*' imgExtensions{i}];
        files = dir(fullfile(trainFolder, pattern));
        fprintf('    查找到%d个%s文件\n', length(files), imgExtensions{i});
        allFiles = [allFiles; files];
    end
    
    if isempty(allFiles)
        error('训练文件夹中未找到图像文件');
    end
    
    fprintf('    共找到%d个图像文件\n', length(allFiles));
    
    % 2. 解析文件名获取人物ID
    fprintf('【步骤2/10】正在解析文件名获取人物ID...\n');
    personIDs = [];
    invalidFiles = 0;
    for i = 1:length(allFiles)
        filename = allFiles(i).name;
        tokens = regexp(filename, '(\d+)[-_](\d+)', 'tokens');
        if ~isempty(tokens)
            personID = str2double(tokens{1}{1});
            personIDs = [personIDs; personID];
        else
            warning('文件名格式不正确，无法提取人物ID: %s', filename);
            invalidFiles = invalidFiles + 1;
        end
    end
    
    fprintf('    成功解析%d个文件，%d个文件格式不符\n', length(personIDs), invalidFiles);
    
    % 3. 获取唯一的人物ID
    fprintf('【步骤3/10】分析人物ID统计...\n');
    uniquePersonIDs = unique(personIDs);
    personCount = length(uniquePersonIDs);
    
    if personCount == 0
        error('无法从文件名中提取人物ID');
    end
    
    fprintf('    识别到%d个不同的人物ID\n', personCount);
    
    % 4. 为每个人选择指定数量的训练图像
    fprintf('【步骤4/10】选择训练图像（每人%d张）...\n', trainImgPerPerson);
    selectedFiles = [];
    trainLabels = [];
    
    for i = 1:personCount
        personID = uniquePersonIDs(i);
        personFileIndices = find(personIDs == personID);
        
        % 确保每个人有足够的图像
        numAvailable = length(personFileIndices);
        numToUse = min(trainImgPerPerson, numAvailable);
        
        if numToUse < trainImgPerPerson
            fprintf('    警告：人物ID %d 只有 %d 张图像可用，少于请求的 %d 张\n', personID, numAvailable, trainImgPerPerson);
        end
        
        % 随机选择图像
        if numToUse > 0
            selectedIndices = personFileIndices(randperm(numAvailable, numToUse));
            selectedFiles = [selectedFiles; allFiles(selectedIndices)];
            trainLabels = [trainLabels; repmat(personID, numToUse, 1)];
            fprintf('    人物ID %d：选择了%d张图像\n', personID, numToUse);
        end
    end
    
    fprintf('    共选择%d张训练图像\n', length(selectedFiles));
    
    % 5. 读取并预处理图像
    fprintf('【步骤5/10】读取并预处理训练图像...\n');
    numImages = length(selectedFiles);
    
    % 读取第一张图像确定尺寸
    fprintf('    读取第一张图像确定尺寸...\n');
    firstImg = imread(fullfile(trainFolder, selectedFiles(1).name));
    if size(firstImg, 3) == 3
        firstImg = rgb2gray(firstImg);
    end
    [imgHeight, imgWidth] = size(firstImg);
    imgSize = imgHeight * imgWidth;
    fprintf('    图像尺寸：%d x %d（%d像素）\n', imgHeight, imgWidth, imgSize);
    
    % 初始化图像矩阵，每列是一个图像向量
    trainFaces = zeros(imgSize, numImages);
    
    % 加载所有图像
    fprintf('    开始读取所有训练图像：\n');
    progressInterval = max(1, round(numImages/20)); % 20次进度显示
    fprintf('    进度：[');
    progressChar = '=';
    for i = 1:numImages
        % 读取图像
        img = imread(fullfile(trainFolder, selectedFiles(i).name));
        
        % 转换为灰度图像
        if size(img, 3) == 3
            img = rgb2gray(img);
        end
        
        % 确保所有图像尺寸一致
        if size(img, 1) ~= imgHeight || size(img, 2) ~= imgWidth
            img = imresize(img, [imgHeight, imgWidth]);
        end
        
        % 转换为列向量
        trainFaces(:, i) = double(img(:));
        
        % 显示进度
        if mod(i, progressInterval) == 0 || i == numImages
            fprintf(progressChar);
        end
    end
    fprintf('] 100%%\n');
    
    % 6. 计算平均脸
    fprintf('【步骤6/10】计算平均脸...\n');
    meanFace = mean(trainFaces, 2);
    fprintf('    平均脸计算完成\n');
    
    % 7. 将每个人脸减去平均脸
    fprintf('【步骤7/10】标准化人脸（减去平均脸）...\n');
    normalizedFaces = trainFaces - meanFace;
    fprintf('    标准化完成\n');
    
    % 8. 计算特征脸
    fprintf('【步骤8/10】计算特征脸...\n');
    fprintf('    正在计算协方差矩阵...\n');
    % 使用紧凑方法计算协方差矩阵的特征向量
    % L = A^T * A，而不是直接计算 C = A * A^T
    L = normalizedFaces' * normalizedFaces;
    fprintf('    协方差矩阵尺寸：%d x %d\n', size(L, 1), size(L, 2));
    
    fprintf('    正在计算特征值和特征向量（可能需要一些时间）...\n');
    [V, D] = eig(L);
    
    % 特征值按升序排序，转换为降序
    fprintf('    对特征值排序...\n');
    [eigenValues, indices] = sort(diag(D), 'descend');
    V = V(:, indices);
    
    % 计算特征脸
    fprintf('    计算特征脸...\n');
    eigenFaces = normalizedFaces * V;
    
    % 归一化特征脸
    fprintf('    正在归一化特征脸...\n');
    for i = 1:size(eigenFaces, 2)
        eigenFaces(:, i) = eigenFaces(:, i) / norm(eigenFaces(:, i));
    end
    fprintf('    特征脸计算完成，共%d个特征脸\n', size(eigenFaces, 2));
    
    % 9. 根据主成分贡献率选择特征脸
    fprintf('【步骤9/10】根据主成分贡献率(%.2f)选择特征脸...\n', pcaRatio);
    totalVariance = sum(eigenValues);
    cumulativeVariance = cumsum(eigenValues) / totalVariance;
    
    % 选取满足贡献率的特征脸数量
    eigIdx = find(cumulativeVariance >= pcaRatio, 1, 'first');
    if isempty(eigIdx)
        eigIdx = length(eigenValues);  % 如果没有满足条件的，使用所有特征脸
    end
    
    % 保留前eigIdx个特征脸
    eigenFaces = eigenFaces(:, 1:eigIdx);
    fprintf('    根据贡献率保留了%d个特征脸，占总方差的%.2f%%\n', eigIdx, cumulativeVariance(eigIdx)*100);
    
    % 10. 计算训练图像在特征空间的投影
    fprintf('【步骤10/10】计算训练图像在特征空间的投影...\n');
    projectMatrix = eigenFaces;
    weightedTrain = projectMatrix' * normalizedFaces;
    fprintf('    投影完成，训练图像降维至%d维特征空间\n', size(weightedTrain, 1));
    
    fprintf('===== PCA人脸识别训练完成 =====\n\n');
end 